/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.yonsei.iwb.sdt;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import java.util.Hashtable;
import java.util.Vector;
import org.yonsei.iwb.sdt.datastructure.rule.DecisionRule;
import org.yonsei.iwb.sdt.datastructure.rule.DecisionRuleComponent;
import org.yonsei.iwb.sdt.ontology.OntologyModel;
import org.yonsei.iwb.sdt.ontology.PropertyArc;
import org.yonsei.iwb.sdt.refinement.DLConstructors;
import org.yonsei.iwb.sdt.refinement.ExpandingHistory;
import org.yonsei.iwb.sdt.util.UtilFunctions;

/**
 *
 * @author DK
 */
public class SDTSearcher {

    private Model model;
    private Hashtable<DecisionRuleComponent, Vector<Resource>> drcInstanceSet;

    public SDTSearcher(Model model) {
        this.model = model;
        this.drcInstanceSet = new Hashtable();
    }

    public SDTSearcher(OntologyModel om) {
        this.model = om.getJenaModel();
        this.drcInstanceSet = new Hashtable();
    }

    public Vector<Resource> getRuleMatcherInstanceSet(DecisionRule dr, Vector<Resource> instanceSet) {
//        System.out.println("DR ## " + dr.toString());

        Vector<Resource> currentNodeSet = instanceSet;
        for (int i = 0; i < dr.size(); i++) {
            DecisionRuleComponent drc = dr.get(i);
//            System.out.println(" - DRC # " + drc.toString() + " / " + drc.getBranchingType());
            if (this.drcInstanceSet.containsKey(drc)) {
//                System.out.println("이미 존재");
                currentNodeSet = this.drcInstanceSet.get(drc);
            } else {
                Vector<Resource> constrainSatisSet = drc.getConditionMatchedResources(this.model);
                Vector<Resource> resultSet = this.getHistoryInstanceSet(drc.getExpandingHistory(), constrainSatisSet);

                if (drc.getBranchingType()) {
                    Vector<Resource> finalResultSet;
                    if (currentNodeSet.isEmpty()) {
//                        System.out.println("기준 리소스 셋이 비어있음");
                        finalResultSet = new Vector(resultSet);
                    } else {
                        finalResultSet = new Vector();
                        for (int j = 0; j < resultSet.size(); j++) {
                            Resource r = resultSet.get(j);
                            if (currentNodeSet.contains(r)) {
                                finalResultSet.add(r);
                            }
                        }
                    }
                    currentNodeSet = finalResultSet;
                } else {
                    currentNodeSet.removeAll(resultSet);
                }
                this.drcInstanceSet.put(drc, UtilFunctions.copyInstanceSet(currentNodeSet));
            }
//            System.out.println("***********************************************************");
//            for (int j = 0; j < currentNodeSet.size(); j++) {
//                Resource r = currentNodeSet.get(j);
//                System.out.println("   DCR set ** " + r.getLocalName());
//            }
//            System.out.println("***********************************************************");
        }
        for (int j = 0; j < currentNodeSet.size(); j++) {
            Resource r = currentNodeSet.get(j);
//            System.out.println("       Final DR set ## " + r.getLocalName());
        }

        return currentNodeSet;
    }

    private Vector<Resource> getHistoryInstanceSet(ExpandingHistory eh, Vector<Resource> startSet) {
        if (eh != null) {
            Vector<PropertyArc> paset = eh.getPropertySet();
            for (int i = 0; i < paset.size(); i++) {
                PropertyArc pa = paset.get(i);
                String quantifier = eh.getQuantifierSet().get(i);
                if (quantifier.equals(DLConstructors.EXISTENTIAL)) {
                    startSet = this.getExistentialInstanceSet(pa, startSet);
                } else {
                    startSet = this.getUniversalInstanceSet(pa, startSet);
                }
            }
        }

        return startSet;
    }

    private Vector<Resource> getExistentialInstanceSet(PropertyArc pa, Vector<Resource> instanceSet) {

        Vector<Resource> existSet = new Vector();
        Property prop = pa.getProperty();
        if (pa.getDirection()) {
            for (int i = 0; i < instanceSet.size(); i++) {
                boolean exist = false;
                Resource r = instanceSet.get(i);
                //            System.out.println("=   "+r.toString());
                ResIterator res = this.model.listResourcesWithProperty(prop, r);
                res:
                while (res.hasNext()) {                    
                    Resource past_r = res.nextResource();
                    if(existSet.contains(past_r)){
                        continue res;
                    }
                    NodeIterator ni = this.model.listObjectsOfProperty(past_r, prop);
                    while (ni.hasNext()) {
                        Resource r2 = ni.nextNode().asResource();
                        if (instanceSet.contains(r2)) {
                            exist = true;
                            break;
                        }
                    }
                    if (exist) {
                        existSet.add(past_r);
                    }
                }
            }
        } else {
            for (int i = 0; i < instanceSet.size(); i++) {
                boolean exist = false;
                Resource r = instanceSet.get(i);
                NodeIterator ni2 = this.model.listObjectsOfProperty(r, prop);
                while (ni2.hasNext()) {
                    Resource past_r = ni2.nextNode().asResource();
                    ResIterator res2 = this.model.listResourcesWithProperty(prop, past_r);
                    while (res2.hasNext()) {
                        Resource r2 = res2.nextResource();
                        if (instanceSet.contains(r2)) {
                            exist = true;
                            break;
                        }
                    }
                    if (exist) {
                        existSet.add(past_r);
                    }
                }
            }
        }
        return existSet;
    }

    private Vector<Resource> getUniversalInstanceSet(PropertyArc pa, Vector<Resource> instanceSet) {

        Property prop = pa.getProperty();
        Vector<Resource> univSet = new Vector();

        if (pa.getDirection()) {
            for (int i = 0; i < instanceSet.size(); i++) {
                boolean universal = true;
                Resource r = instanceSet.get(i);
                ResIterator res = this.model.listResourcesWithProperty(prop, r);
                while (res.hasNext()) {
                    Resource past_r = res.nextResource();
                    NodeIterator ni = this.model.listObjectsOfProperty(past_r, prop);

                    while (ni.hasNext()) {
                        Resource r2 = ni.nextNode().asResource();
                        if (!instanceSet.contains(r2)) {
                            universal = false;
                            break;
                        }
                    }
                    if (universal) {
                        univSet.add(past_r);
                    }
                }
            }
        } else {
            for (int i = 0; i < instanceSet.size(); i++) {
                boolean universal = true;
                Resource r = instanceSet.get(i);
                NodeIterator ni = this.model.listObjectsOfProperty(r, prop);
                while (ni.hasNext()) {
                    Resource past_r = ni.nextNode().asResource();
                    ResIterator res = this.model.listResourcesWithProperty(prop, past_r);
                    while (res.hasNext()) {
                        Resource r2 = res.nextResource();
                        if (!instanceSet.contains(r2)) {
                            universal = false;
                            break;
                        }
                    }
                    if (universal) {
                        univSet.add(past_r);
                    }
                }
            }
        }
        return univSet;
    }
}
